﻿///@author Rafał Hazan
///@email  rafal.hazan@gmail.com\

#include "PopulationInitializer.h"
#include "EvolutionaryAlgorithm.h"
#include "StopCondition.h"
#include "SelectOperator.h"
#include "CrossoverOperator.h"
#include "MutationOperator.h"
#include "ReplacementOperator.h"
#include "Configuration.h"
#include "Printer.h"

#include "MatrixGraph.h"
#include "Genotype.h"
#include "RandomGenerator.h"

long EvolutionaryAlgorithm::iterationNo = 0;

EvolutionaryAlgorithm::EvolutionaryAlgorithm(PopulationInitializer & initializer, 
		StopCondition & stop, 
		SelectOperator & select, 
		CrossoverOperator & crossover, 
		MutationOperator & mutation, 
		ReplacementOperator & replacement)
		: _initializer(initializer), _stop(stop), _selection(select), _crossover(crossover), _mutation(mutation), _replacement(replacement)
{
}

void EvolutionaryAlgorithm::perform(const MatrixGraph & graph)
{
	RandomGenerator random;

	population = _initializer.init(graph);
	int x = 1;
	EvolutionaryAlgorithm::iterationNo = 0;
	while( _stop.isNotFulfilled(population) )
	{
		population_type children;
		for (int i = 0; i < Configuration::lambda; ++i)
		{
			if (random.getRandomToOne() < Configuration::pc)
			{
				population_type gens = _selection.select(Configuration::selectPairs * 2, population); // wybieranych jest dwoje rodzicow
				population_type::const_iterator genIter = gens.begin();
				while (genIter != gens.end())
				{//std::cout<<"a"<<gens.size();
					Genotype gen1 = Genotype(graph);
					gen1.gens = genIter->gens;
					++genIter;
					Genotype gen2 = Genotype(graph);
					gen2.gens = genIter->gens;
					population_type tmp = _mutation.mutate(_crossover.cross(gen1, gen2));
					children.insert(tmp.begin(), tmp.end());
					++genIter;
				}
				//std::cout<<std::endl;
			}
			else
			{
				population_type selected = _selection.select(1, population); // wybierany jest jeden potomek
				population_type tmp = _mutation.mutate(selected);
				children.insert(tmp.begin(), tmp.end());
				//population.erase(*selected.begin()); // Ze starej populacji usuwamy, bo zmutowane są przynajmniej takie same.
			}
		}
		population = _replacement.replace(population, children);
		//if (x == 4)break;++x;

		++EvolutionaryAlgorithm::iterationNo;
		//if (iteration % 100 == 0)
		//{
			std::cout<< "iteracja " << EvolutionaryAlgorithm::iterationNo << std::endl;
			std::cout << "=ACTUAL_BEST=" << *population.begin() << "fitness val " << population.begin()->fitnessValue << std::endl;
			//Printer::ciout(population);
		//}
	}
	//Printer::ciout(population);
}